﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CSharp;
using System.Reflection;
using System.CodeDom.Compiler;

namespace AnaxibiaStudios.Smug.Internal
{
  public class Compiler
  {
    public bool GenerateInMemory { get; set; }

    public Compiler()
    {
      GenerateInMemory = true;
    }

    public Type Compile(Type targetType, string source, List<Assembly> references, string dotNetVersion)
    {
      var providerOptions = new Dictionary<string, string>();
      providerOptions.Add("CompilerVersion", dotNetVersion);

      var codeProvider = new CSharpCodeProvider(providerOptions);

      var options = new System.CodeDom.Compiler.CompilerParameters()
      {
        CompilerOptions = "",
        TreatWarningsAsErrors = false,
        IncludeDebugInformation = true,
        GenerateInMemory = GenerateInMemory,
        GenerateExecutable = false
      };

      foreach (var asm in references)
      {
        options.ReferencedAssemblies.Add(asm.Location);
      }
      
      var compilerResults = codeProvider.CompileAssemblyFromSource(options, source);

      if (compilerResults.Errors.Count > 0)
      {
        InterpretCompilerErrors(targetType, compilerResults.Errors.Cast<CompilerError>().ToList(), source);
      }

      var assembly = compilerResults.CompiledAssembly;
      return assembly.GetTypes().FirstOrDefault(t => t.Name.StartsWith("Proxy"));
    }

    private void InterpretCompilerErrors(Type targetType, List<CompilerError> list, string source)
    {
      var first = list.First();
      string msg;

      if (first.ErrorNumber == "CS0246")
      {
        msg = "Insufficient reference data: " + first.ErrorText;
      }
      else
      {
        msg = string.Join("\r\n", list.Select(ex => ex.ErrorText));
      }

      throw new SmugCompilationException(targetType, msg, source);
    }
  }
}
